#ifndef JNCINTERFACE_H
#define JNCINTERFACE_H


#include <typeinfo>
#include <assert.h>
#include "jncDefs.h"
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/shared_ptr.hpp>

// Interface required by any objects wishing 
// to be called from xml

/* extern bool testClass(jncTypev&); */

const char* getTypeName(jncTypev& v);

#define ITRARGV(z, n, seq) seq[n]
#define ITRARGL(z, n, data) data 

#define LINE1(n)	    case n:					\
  return (*(static_cast<BOOST_PP_CAT(boost::function, BOOST_PP_INC(n))<gReturnCode, 
#define LINE2(n, data)						\
  BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, ITRARGL, jncTypev)>* >(data.getHandle())))(this BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, ITRARGV, data.argv)); \
  break;

#define MERGELINE(z, n, data) \
  LINE1(n) BOOST_PP_SEQ_ELEM(0, data)* LINE2(n, BOOST_PP_SEQ_ELEM(1, data))

#define EXPANDBRANCH(type, cxt)     switch(cxt.getArgSize()) {	\
    BOOST_PP_REPEAT(JINC_MAX_ARG, MERGELINE, (type)(cxt))	\
      default : assert(0);					\
  };

#define PRINTN(z, n, data)     BOOST_PP_CAT(data, n)
#define PRINTA(z, n, data)   jncTypev BOOST_PP_CAT(data, n) = jncTypev()
#define REPEATA(n,data) BOOST_PP_ENUM(n, PRINTA, data)

#define EXARG(z, n, data)     jncTypev BOOST_PP_CAT(v, n) = jncTypev()
#define EXPANDEFARG(n) BOOST_PP_ENUM(n, EXARG, ~)

#define COELM(z, n, data)     if(!(BOOST_PP_CAT(v, n).empty())){	\
    data BOOST_PP_CAT(y, n)(boost::any_cast<data>(BOOST_PP_CAT(v, n)));	\
    memcpy((void*)&x[(sizeof(x)/sizeof(data))], BOOST_PP_CAT(&y, n), sizeof(data)); \
  }
#define CONCATELM(type) BOOST_PP_REPEAT(BOOST_PP_SUB(JINC_MAX_ARG, 2), COELM, type)

#define COLLECT(z, n, data)     arg[n] = BOOST_PP_CAT(v, n);
#define COLLECTARG     BOOST_PP_REPEAT(BOOST_PP_SUB(JINC_MAX_ARG, 2), COLLECT, ~)

extern std::vector<jncTypev> collectArg(REPEATA(BOOST_PP_DEC(JINC_MAX_ARG), v));
extern int getValidArg(std::vector<jncTypev>&);

#define JNCINTERFACEIMPL(atype, type)					\
  public :								\
  typedef gReturnCode (atype::*callBack)();				\
  inline virtual const char* runtimeSymbol() const			\
  {									\
    return typeid(*this).name();					\
  }									\
  inline virtual  gReturnCode makeCopy(jncTypev v = jncTypev())		\
  {									\
    if(v.empty())							\
      return v;								\
    try {								\
      __inst = boost::any_cast<type*>(v);				\
      return gReturnCode(new type*(__inst));				\
    }									\
    catch(boost::bad_any_cast& e)					\
      {									\
	std::string msg("Conversion from ");				\
	msg += std::string(std::string(getTypeName(v)) + " to ") + runtimeSymbol(); \
	throw RnException(ECONV, msg.c_str(), e);			\
      }									\
  }									\
  inline virtual gReturnCode makeArray(jncTypev v = jncTypev())		\
  {									\
    int n;								\
    if(v.empty() || ((n = numberConv(v)) <= -1))			\
      n = 0;								\
    type* x = NULL;							\
    if(n)								\
      x = (type*)malloc(n*sizeof(type));				\
    return gReturnCode(new type*(x));					\
  }									\
  inline virtual gReturnCode indexArray(jncTypev p = jncTypev(), jncTypev i = jncTypev(), jncTypev v = jncTypev()) \
  {									\
    int n;								\
    if(!p.empty())							\
      {									\
	if(i.empty() || ((n = numberConv(i)) <= -1))			\
	 return gReturnCode(new type*(NULL));				\
      }									\
    else								\
      return gReturnCode(new type*(NULL));				\
    type* arr = NULL;							\
    type* val;								\
    try {								\
      type* arr = *(boost::any_cast<type**>(p));			\
    }									\
    catch(boost::bad_any_cast& e)					\
      {									\
	std::string msg("Conversion from ");				\
	msg += std::string(std::string(getTypeName(p)) + " to ") + runtimeSymbol(); \
	throw RnException(ECONV, msg.c_str(), e);			\
      }									\
    try {								\
      if(!v.empty())							\
	val = boost::any_cast<type*>(v);				\
      else								\
	return gReturnCode(arr + (n*sizeof(type)));			\
    }									\
    catch(boost::bad_any_cast& e)					\
      {									\
	std::string msg("Conversion from ");				\
	msg += std::string(std::string(getTypeName(v)) + " to ") + runtimeSymbol(); \
	throw RnException(ECONV, msg.c_str(), e);			\
      }									\
    memcpy((void*)(arr + (n*sizeof(type))), (void*)val, sizeof(type));	\
    return gReturnCode(arr + (n*sizeof(type)));				\
  }									\
  inline virtual gReturnCode makePtrArray(jncTypev v = jncTypev())	\
  {									\
    int n;								\
    type** x = NULL;							\
    if(v.empty() || ((n = numberConv(v)) <= -1))			\
      n = 0;								\
    if(n)								\
      x = (type**)malloc(n*sizeof(type*));				\
    return gReturnCode(new type**(x));					\
  }									\
  inline virtual gReturnCode indexPtrArray(jncTypev p = jncTypev(), jncTypev i = jncTypev(), jncTypev v = jncTypev()) \
  {									\
    int n;								\
    if(!p.empty())							\
      {									\
	if(i.empty() || ((n = numberConv(i)) <= -1))			\
	  return gReturnCode(new type**(NULL));				\
      }									\
    else								\
      return gReturnCode(new type**(NULL));				\
    type** arr = NULL;							\
    type** val = NULL;							\
    try {								\
      type** arr = boost::any_cast<type**>(p);				\
    }									\
    catch(boost::bad_any_cast& e)					\
      {									\
	std::string msg("Conversion from ");				\
	msg += std::string(std::string(getTypeName(p)) + " to ") + runtimeSymbol(); \
	throw RnException(ECONV, msg.c_str(), e);			\
      }									\
    try {								\
      if(!v.empty())							\
	val = boost::any_cast<type**>(v);				\
      else								\
	return gReturnCode((type**)new type*(*arr + (n*sizeof(type))));	\
    }									\
    catch(boost::bad_any_cast& e)					\
      {									\
	std::string msg("Conversion from ");				\
	msg += std::string(std::string(getTypeName(v)) + " to ") + runtimeSymbol(); \
	throw RnException(ECONV, msg.c_str(), e);			\
      }									\
    memcpy((void*)(*arr + (n*sizeof(type*))), (void*)val, sizeof(type*)); \
    return gReturnCode((type**)new type*(*arr + (n*sizeof(type))));	\
  }									\
  inline virtual gReturnCode  CallMember(CallBackParam cn)		\
  {									\
    EXPANDBRANCH(atype, cn)						\
      }									\
  inline virtual void injectNewCopy(jncTypev& v) throw(boost::bad_any_cast&) \
  {									\
    try {								\
      __inst = boost::any_cast<type*>(v);				\
    }									\
    catch(boost::bad_any_cast& e)					\
      {									\
	std::string msg("Conversion from ");				\
	msg += std::string(std::string(getTypeName(v)) + " to ") + runtimeSymbol(); \
	throw RnException(ECONV, msg.c_str(), e);			\
      }									\
  }									\
  private :								\
  type* __inst;								

class JncInterface {
 public:
  virtual const char* runtimeSymbol() const = 0;
  virtual gReturnCode makeCopy(jncTypev v = jncTypev()) = 0;
  virtual gReturnCode makeArray(jncTypev v = jncTypev()) = 0;
  virtual gReturnCode indexArray(jncTypev v = jncTypev(), jncTypev v0 = jncTypev(), jncTypev v1 = jncTypev()) = 0;
  virtual gReturnCode makePtrArray(jncTypev v = jncTypev()) = 0;
  virtual gReturnCode indexPtrArray(jncTypev v = jncTypev(), jncTypev v0 = jncTypev(), jncTypev v1 = jncTypev()) = 0;
  inline virtual ~JncInterface() {}
  virtual gReturnCode CallMember(CallBackParam) = 0;
  virtual void injectNewCopy(jncTypev&) throw(boost::bad_any_cast&) = 0;
};

EXPANDBRANCH(TYPE, FNARG)


#endif
